package name.pilgr.soaboard.model;

import java.util.Observable;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

/**
 * @author masny
 * Encapsulate service for retrieve and store various data
 */
public abstract class DataService extends Observable{
	protected int MAX_NUMBER_FAILED_REQUEST;
	private int currentHash = 0;
	private int numberFailedRequest = 0;
	private long refreshPeriod = 0;
	private Exception lastException = null;

	/**
	 *Actual data at current time. 
	 */
	//String currentData = "";
	Vector<Vector<String>> currentData;
	/**
	 *Timer for periodically retrieve and processing data  
	 */
	Timer timer;
	TimerTask timerTask;

	/**
	 * @param refreashPeriod Period in milliseconds to retrieve and refresh data
	 */
	public DataService(long refreshPeriod) {
		this();
		initTimer();
		setCurrentHash(currentData.hashCode());
		startRefresh(refreshPeriod);
	}
	
	public DataService() {
		currentData = new Vector<Vector<String>>();
	}
	
	void initTimer() {
		timer = new Timer(true);
		timerTask = new TimerTask() {

			@Override
			public void run() {
				getNewData();
			}

		};
	}
	
	/**
	 * Retrieve new data from data source and store it (if history feature enabled)  
	 */
	abstract boolean requestData();
	
	private synchronized void getNewData(){
		//Normal flow
		if (requestData()) {
			setChanged();
			notifyObservers();
		}
		//Error handling and notifying to UI
		if (getNumberFailedRequest() >= MAX_NUMBER_FAILED_REQUEST) {
			stopRefresh();					
		}
		if (lastException != null) {
			notifyObserversError();
		}
	}
	
	public void forcedRequestData(){
		getNewData();
	}

	public Vector<Vector<String>> getCurrentData() {
		return currentData;
	}
	
	public void stopRefresh() {
		timer.cancel();
	}
	
	public void startRefresh(long refreshPeriod) {
		this.refreshPeriod = refreshPeriod;
		timer.schedule(timerTask, 0, refreshPeriod);
	}
	
	public void startRefresh() {
		if (refreshPeriod != 0) {
			timer.schedule(timerTask, 0, refreshPeriod);
		}
	}
	
	private void notifyObserversError() {
		setChanged();
		notifyObservers(lastException);		
	}
	
	int getNumberFailedRequest() {
		return numberFailedRequest;
	}

	void setNumberFailedRequest(int numberFailedRequest) {
		this.numberFailedRequest = numberFailedRequest;
	}

	int getCurrentHash() {
		return currentHash;
	}

	void setCurrentHash(int currentHash) {
		this.currentHash = currentHash;
	}
	
	Exception getLastException() {
		return lastException;
	}

	void setLastException(Exception lastException) {
		this.lastException = lastException;
	}

}
